#include <mips/regdef.h>
#include <sys/syscall.h>

		.text
		.align          2
		.globl          main
		.ent            main
main:
		.frame          $fp, 32, ra
		.set            noreorder 
		.cpload         t9        
		.set            reorder   
		subu            sp, sp, 32
		.cprestore      20
		sw              ra, 28(sp)
		sw              $fp,24(sp)
		sw              gp, 20(sp)
		move            $fp,sp
leer:
		# leemos 1 carater por stdin
		li              v0, SYS_read
		li              a0, 0
		la              a1, 16(sp)
		li              a2, 1
		syscall
		
		# chequeamos posibles errores
		bnez            a3, final
		li              t0, 1                #a3==0
		bne             v0, t0, final        #si no se leyeron 1 caracteres, salir

		# chequeamos enter y espacios
		lbu             a0, 16(sp)
		lbu             t0, espacio          # if(a0 == ' ') goto leer;
		beq             a0, t0,leer
		li              t0, 0x0A
		beq             a0, t0, leer         # if(a0 == 0x0A) goto leer;
		li              t0, 0x00
		beq             a0, t0, leer         # if(a0 == 0x00) goto leer;

		# leemos el caracter faltante por stdin
		li              v0, SYS_read
		li              a0, 0
		la              a1, 17(sp)
		li              a2, 1
		syscall
		
		# chequeamos posibles errores
		bnez            a3, final
		li              t0, 1                #a3==0
		bne             v0, t0, final        #si no se leyeron 1 caracteres, salir

		# guardamos ambos caracteres en argumentos y llamamos a hex2bin
		lbu             a0, 16(sp)
		lbu             a1, 17(sp)
		jal             hex2bin
		sb              v0, 16(sp)

		# chequeamos posibles errores de conversion
		lw              v0, valido
		beqz            v0, final

		# escribimos el caracter obtenido a stdout
		li              v0, SYS_write
		li              a0, 1
		la              a1, 16(sp)
		li              a2, 1
		syscall
		
		#chequeamos posibles errores
		bnez            a3, final            # if (a3 != 0) return
		li              t0, 1
		bne             v0, t0, final        # if (v0 != 1) return

		# leemos los siguientes dos caracteres a procesar
		b               leer
final:
		move            v0, zero
		move            sp, $fp
		lw              gp, 20(sp)
		lw              $fp,24(sp)
		lw              ra, 28(sp)
		addu            sp, sp, 32
		j               ra
  
		.end main

#---------------------------------------------------#

		.ent hex2bin
hex2bin:
		.frame          $fp, 16, ra
		.set            noreorder
		.cpload         t9
		.set            reorder
		subu            sp, sp, 16
		.cprestore      0
		sw              $fp, 12(sp)
		sw              gp, 8(sp)
		sw		ra, 4(sp)
		move            $fp, sp

		# guardamos los argumentos pasados en el stack del caller
		sb              a0, 16(sp)
		sb              a1, 17(sp)
		
		# char primeroConvertido = convertirNibble(primerNibble);
		lb              a0, 16(sp)
		jal             convertirNibble
		move            t0, v0

		# char segundoConvertido = convertirNibble(segundoNibble);
		lb              a0, 17(sp)
		jal             convertirNibble
		move            t1, v0

		# resultado = (primeroConvertido << 4) + segundoConvertido;
		sll             t0, t0, 4
		add             t0, t0, t1

		#guardamos resultado en v0 y destruimos el stack frame
		move            v0, t0
		move            sp, $fp
		lw              ra, 4(sp)
		lw              gp, 8(sp)
		lw              $fp, 12(sp)
		addu            sp, sp, 16
		j               ra

		.end      hex2bin


#---------------------------------------------------#

		.ent convertirNibble
convertirNibble:
		.frame          $fp, 16, ra
		.set            noreorder
		.cpload         t9
		.set            reorder
		subu            sp, sp, 16
		.cprestore      0
		sw              $fp, 12(sp)
		sw              gp, 8(sp)
		sw              ra, 4(sp)
		move            $fp, sp

		#hacemos los if sobre a0 y guardamos el resultado en v0

	#chequeamos: if(nibble >= 'a' && nibble <= 'f')
		blt             a0, 0x61, noLetraMinuscula     # 'a'
		bgt             a0, 0x66, noLetraMinuscula     # 'f'
		
		#si es letra minuscula valida...
		sub            v0, a0, 0x57          # v0 = a0 - 'a' + 10
		b finConvertirNibble
	noLetraMinuscula:

	#chequeamos: if(nibble >= 'A' && nibble <= 'F')
		blt             a0, 0x41, noLetraMayuscula     # 'A'
		bgt             a0, 0x46, noLetraMayuscula     # 'F'
		#si es letra mayuscula valida...
		sub             v0, a0, 0x37         # v0 = a0 - 'A' + 10
		b finConvertirNibble
	noLetraMayuscula:

	#chequeamos: if(nibble >= '0' && nibble <= '9')
		blt             a0, 0x30, noNumero # '0'
		bgt             a0, 0x39, noNumero # '9'
		#si es un numero...
		sub             v0, a0, 0x30  # v0 = a0 - '0'
		b finConvertirNibble
	noNumero:

	#si llego hasta aca es porque no es valido.

		li              v0, 0
		sw              v0, valido # guardamos la variable global valido=0

finConvertirNibble:
		#destruimos el stack frame
		move            sp, $fp
		lw              gp, 8(sp)
		lw              $fp, 12(sp)
		addu            sp, sp, 16
		j               ra

		.end      convertirNibble


#---------------------------------------------------#

		.data
valido:         .word 1 # true
newline:        .asciiz "\n" 
espacio:        .asciiz " " 

